"""
样式应用器
负责将模板样式应用到PPT幻灯片，包括字体、颜色、布局和间距控制。
"""

import logging
from typing import Dict, List, Optional, Any, Tuple
from pathlib import Path

from pptx.util import Inches, Pt
from pptx.enum.text import PP_ALIGN, MSO_ANCHOR
from pptx.enum.shapes import MSO_SHAPE
from pptx.dml.color import RGBColor
from pptx.enum.dml import MSO_THEME_COLOR
from pptx.shapes.base import BaseShape
from pptx.text.text import TextFrame
from pptx.slide import Slide

from ..models.template_config import TemplateConfig, FontConfig, ColorScheme, LayoutConfig

logger = logging.getLogger(__name__)


class StyleApplicator:
    """
    样式应用器类
    
    负责将模板配置应用到PPT幻灯片的各个元素
    """
    
    def __init__(self):
        """初始化样式应用器"""
        # 预定义的图片占位符样式
        self.image_placeholder_styles = {
            "border_width": Pt(2),
            "corner_radius": Pt(5),
            "shadow_offset": Pt(3)
        }
        
        # 预定义的形状样式
        self.shape_styles = {
            "default_border_width": Pt(1),
            "default_corner_radius": Pt(3)
        }
    
    def apply_slide_style(
        self, 
        slide: Slide, 
        template_config: TemplateConfig,
        slide_type: str = "content_slide"
    ):
        """
        应用幻灯片整体样式
        
        Args:
            slide: 幻灯片对象
            template_config: 模板配置
            slide_type: 幻灯片类型
        """
        try:
            # 设置背景样式
            self._apply_background_style(slide, template_config)
            
            # 应用布局配置
            layout_config = template_config.style.layouts.get(slide_type)
            if layout_config:
                self._apply_layout_style(slide, layout_config, template_config)
            
            logger.debug(f"幻灯片样式应用成功: {slide_type}")
            
        except Exception as e:
            logger.error(f"应用幻灯片样式失败: {e}")
    
    def apply_text_style(
        self,
        text_frame: TextFrame,
        font_type: str,
        template_config: TemplateConfig,
        custom_color: Optional[str] = None
    ):
        """
        应用文本样式
        
        Args:
            text_frame: 文本框对象
            font_type: 字体类型 (title, heading, body, caption)
            template_config: 模板配置
            custom_color: 自定义颜色（可选）
        """
        try:
            font_config = template_config.style.fonts.get(font_type)
            if not font_config:
                logger.warning(f"字体配置不存在: {font_type}")
                return
            
            # 获取颜色
            color = custom_color or font_config.color
            
            # 应用到所有段落
            for paragraph in text_frame.paragraphs:
                self._apply_paragraph_style(paragraph, font_config, color)
            
            # 设置文本框属性
            self._apply_text_frame_properties(text_frame, template_config)
            
        except Exception as e:
            logger.error(f"应用文本样式失败: {e}")
    
    def apply_shape_style(
        self,
        shape: BaseShape,
        template_config: TemplateConfig,
        shape_type: str = "default"
    ):
        """
        应用形状样式
        
        Args:
            shape: 形状对象
            template_config: 模板配置
            shape_type: 形状类型
        """
        try:
            # 应用填充样式
            self._apply_shape_fill(shape, template_config, shape_type)
            
            # 应用边框样式
            self._apply_shape_border(shape, template_config)
            
            # 应用阴影效果
            if template_config.style.shadow_enabled:
                self._apply_shape_shadow(shape, template_config)
            
            # 应用圆角效果
            if template_config.style.border_radius > 0:
                self._apply_shape_corner_radius(shape, template_config.style.border_radius)
            
        except Exception as e:
            logger.error(f"应用形状样式失败: {e}")
    
    def create_styled_image_placeholder(
        self,
        slide: Slide,
        left: float,
        top: float,
        width: float,
        height: float,
        template_config: TemplateConfig,
        placeholder_text: str = "图片占位符"
    ) -> BaseShape:
        """
        创建带样式的图片占位符
        
        Args:
            slide: 幻灯片对象
            left: 左边距
            top: 上边距
            width: 宽度
            height: 高度
            template_config: 模板配置
            placeholder_text: 占位符文本
            
        Returns:
            BaseShape: 创建的占位符形状
        """
        try:
            # 创建矩形作为图片占位符
            placeholder = slide.shapes.add_shape(
                MSO_SHAPE.RECTANGLE,
                Inches(left), Inches(top),
                Inches(width), Inches(height)
            )
            
            # 设置填充样式
            fill = placeholder.fill
            fill.solid()
            # 使用浅色背景
            bg_rgb = self._hex_to_rgb(template_config.style.color_scheme.background)
            bg_color = self._lighten_color(bg_rgb, 0.95)
            fill.fore_color.rgb = RGBColor(*bg_color)
            
            # 设置边框
            line = placeholder.line
            line.color.rgb = RGBColor(*self._hex_to_rgb(template_config.style.color_scheme.border))
            line.width = self.image_placeholder_styles["border_width"]
            
            # 添加占位符文本
            if placeholder.has_text_frame:
                text_frame = placeholder.text_frame
                text_frame.clear()
                p = text_frame.paragraphs[0]
                p.text = placeholder_text
                p.alignment = PP_ALIGN.CENTER
                
                # 设置文本垂直居中
                text_frame.vertical_anchor = MSO_ANCHOR.MIDDLE
                
                # 应用字体样式
                self._apply_paragraph_style(
                    p, 
                    template_config.style.fonts["caption"],
                    template_config.style.color_scheme.text_secondary
                )
            
            return placeholder
            
        except Exception as e:
            logger.error(f"创建图片占位符失败: {e}")
            return None
    
    def create_styled_chart_placeholder(
        self,
        slide: Slide,
        left: float,
        top: float,
        width: float,
        height: float,
        template_config: TemplateConfig,
        chart_type: str = "柱状图"
    ) -> BaseShape:
        """
        创建带样式的图表占位符
        
        Args:
            slide: 幻灯片对象
            left: 左边距
            top: 上边距
            width: 宽度
            height: 高度
            template_config: 模板配置
            chart_type: 图表类型
            
        Returns:
            BaseShape: 创建的占位符形状
        """
        try:
            # 创建圆角矩形作为图表占位符
            placeholder = slide.shapes.add_shape(
                MSO_SHAPE.ROUNDED_RECTANGLE,
                Inches(left), Inches(top),
                Inches(width), Inches(height)
            )
            
            # 设置填充样式 - 使用主色调的浅色版本
            fill = placeholder.fill
            fill.solid()
            primary_light = self._lighten_color(
                self._hex_to_rgb(template_config.style.color_scheme.primary), 
                0.9
            )
            fill.fore_color.rgb = RGBColor(*primary_light)
            
            # 设置边框
            line = placeholder.line
            line.color.rgb = RGBColor(*self._hex_to_rgb(template_config.style.color_scheme.primary))
            line.width = Pt(2)
            
            # 添加图表类型文本
            if placeholder.has_text_frame:
                text_frame = placeholder.text_frame
                text_frame.clear()
                p = text_frame.paragraphs[0]
                p.text = f"{chart_type}占位符"
                p.alignment = PP_ALIGN.CENTER
                
                # 设置文本垂直居中
                text_frame.vertical_anchor = MSO_ANCHOR.MIDDLE
                
                # 应用字体样式
                self._apply_paragraph_style(
                    p,
                    template_config.style.fonts["body"],
                    template_config.style.color_scheme.primary
                )
            
            return placeholder
            
        except Exception as e:
            logger.error(f"创建图表占位符失败: {e}")
            return None
    
    def apply_layout_spacing(
        self,
        slide: Slide,
        layout_config: LayoutConfig,
        template_config: TemplateConfig
    ):
        """
        应用布局和间距控制
        
        Args:
            slide: 幻灯片对象
            layout_config: 布局配置
            template_config: 模板配置
        """
        try:
            # 调整现有形状的位置和间距
            shapes = list(slide.shapes)
            
            # 获取内容区域配置
            content_area = layout_config.content_area
            
            # 使用固定的幻灯片尺寸（16:9比例）
            slide_width = Inches(13.33)
            slide_height = Inches(7.5)
            
            # 计算实际的内容区域
            content_left = slide_width * content_area["x"]
            content_top = slide_height * content_area["y"]
            content_width = slide_width * content_area["width"]
            content_height = slide_height * content_area["height"]
            
            # 应用间距到文本形状
            for shape in shapes:
                if shape.has_text_frame:
                    self._apply_text_spacing(shape.text_frame, layout_config)
            
            logger.debug("布局间距应用成功")
            
        except Exception as e:
            logger.error(f"应用布局间距失败: {e}")
    
    def check_style_consistency(
        self,
        slide: Slide,
        template_config: TemplateConfig
    ) -> Dict[str, Any]:
        """
        检查模板样式一致性
        
        Args:
            slide: 幻灯片对象
            template_config: 模板配置
            
        Returns:
            Dict: 一致性检查结果
        """
        try:
            consistency_report = {
                "consistent": True,
                "issues": [],
                "suggestions": []
            }
            
            # 检查字体一致性
            font_issues = self._check_font_consistency(slide, template_config)
            if font_issues:
                consistency_report["issues"].extend(font_issues)
                consistency_report["consistent"] = False
            
            # 检查颜色一致性
            color_issues = self._check_color_consistency(slide, template_config)
            if color_issues:
                consistency_report["issues"].extend(color_issues)
                consistency_report["consistent"] = False
            
            # 检查布局一致性
            layout_issues = self._check_layout_consistency(slide, template_config)
            if layout_issues:
                consistency_report["issues"].extend(layout_issues)
                consistency_report["consistent"] = False
            
            return consistency_report
            
        except Exception as e:
            logger.error(f"样式一致性检查失败: {e}")
            return {"consistent": False, "issues": [str(e)], "suggestions": []}
    
    def _apply_background_style(self, slide: Slide, template_config: TemplateConfig):
        """应用背景样式"""
        try:
            background = slide.background
            fill = background.fill
            fill.solid()
            
            # 设置背景颜色
            bg_color = self._hex_to_rgb(template_config.style.color_scheme.background)
            fill.fore_color.rgb = RGBColor(*bg_color)
            
        except Exception as e:
            logger.warning(f"设置背景样式失败: {e}")
    
    def _apply_layout_style(self, slide: Slide, layout_config: LayoutConfig, template_config: TemplateConfig):
        """应用布局样式"""
        try:
            # 这里可以根据布局配置调整幻灯片元素的位置和大小
            # 由于python-pptx的限制，主要通过间距配置来影响布局
            pass
        except Exception as e:
            logger.warning(f"应用布局样式失败: {e}")
    
    def _apply_paragraph_style(self, paragraph, font_config: FontConfig, color_hex: str):
        """应用段落样式"""
        try:
            for run in paragraph.runs:
                font = run.font
                font.name = font_config.family
                font.size = Pt(font_config.size)
                
                # 设置字体粗细
                if font_config.weight == "bold":
                    font.bold = True
                elif font_config.weight == "light":
                    font.bold = False
                else:
                    font.bold = False
                
                # 设置字体颜色
                rgb_color = self._hex_to_rgb(color_hex)
                font.color.rgb = RGBColor(*rgb_color)
                
        except Exception as e:
            logger.warning(f"应用段落样式失败: {e}")
    
    def _apply_text_frame_properties(self, text_frame: TextFrame, template_config: TemplateConfig):
        """应用文本框属性"""
        try:
            # 设置文本框边距
            text_frame.margin_left = Inches(0.1)
            text_frame.margin_right = Inches(0.1)
            text_frame.margin_top = Inches(0.05)
            text_frame.margin_bottom = Inches(0.05)
            
            # 设置自动调整大小
            text_frame.auto_size = None
            
        except Exception as e:
            logger.warning(f"设置文本框属性失败: {e}")
    
    def _apply_shape_fill(self, shape: BaseShape, template_config: TemplateConfig, shape_type: str):
        """应用形状填充"""
        try:
            if hasattr(shape, 'fill'):
                fill = shape.fill
                fill.solid()
                
                # 根据形状类型选择颜色
                if shape_type == "accent":
                    color = template_config.style.color_scheme.accent
                elif shape_type == "secondary":
                    color = template_config.style.color_scheme.secondary
                else:
                    color = template_config.style.color_scheme.background
                
                rgb_color = self._hex_to_rgb(color)
                fill.fore_color.rgb = RGBColor(*rgb_color)
                
        except Exception as e:
            logger.warning(f"应用形状填充失败: {e}")
    
    def _apply_shape_border(self, shape: BaseShape, template_config: TemplateConfig):
        """应用形状边框"""
        try:
            if hasattr(shape, 'line'):
                line = shape.line
                border_color = self._hex_to_rgb(template_config.style.color_scheme.border)
                line.color.rgb = RGBColor(*border_color)
                line.width = self.shape_styles["default_border_width"]
                
        except Exception as e:
            logger.warning(f"应用形状边框失败: {e}")
    
    def _apply_shape_shadow(self, shape: BaseShape, template_config: TemplateConfig):
        """应用形状阴影"""
        try:
            # python-pptx对阴影的支持有限，这里做基础设置
            pass
        except Exception as e:
            logger.warning(f"应用形状阴影失败: {e}")
    
    def _apply_shape_corner_radius(self, shape: BaseShape, radius: int):
        """应用形状圆角"""
        try:
            # python-pptx对圆角的支持有限
            pass
        except Exception as e:
            logger.warning(f"应用形状圆角失败: {e}")
    
    def _apply_text_spacing(self, text_frame: TextFrame, layout_config: LayoutConfig):
        """应用文本间距"""
        try:
            spacing_config = layout_config.spacing
            
            for paragraph in text_frame.paragraphs:
                # 设置行间距
                paragraph.space_after = Pt(spacing_config.get("line", 20))
                
        except Exception as e:
            logger.warning(f"应用文本间距失败: {e}")
    
    def _check_font_consistency(self, slide: Slide, template_config: TemplateConfig) -> List[str]:
        """检查字体一致性"""
        issues = []
        try:
            expected_fonts = set(config.family for config in template_config.style.fonts.values())
            
            for shape in slide.shapes:
                if shape.has_text_frame:
                    for paragraph in shape.text_frame.paragraphs:
                        for run in paragraph.runs:
                            if run.font.name and run.font.name not in expected_fonts:
                                issues.append(f"发现非模板字体: {run.font.name}")
            
        except Exception as e:
            issues.append(f"字体一致性检查失败: {e}")
        
        return issues
    
    def _check_color_consistency(self, slide: Slide, template_config: TemplateConfig) -> List[str]:
        """检查颜色一致性"""
        issues = []
        try:
            # 这里可以实现更详细的颜色一致性检查
            pass
        except Exception as e:
            issues.append(f"颜色一致性检查失败: {e}")
        
        return issues
    
    def _check_layout_consistency(self, slide: Slide, template_config: TemplateConfig) -> List[str]:
        """检查布局一致性"""
        issues = []
        try:
            # 这里可以实现布局一致性检查
            pass
        except Exception as e:
            issues.append(f"布局一致性检查失败: {e}")
        
        return issues
    
    def _hex_to_rgb(self, hex_color: str) -> Tuple[int, int, int]:
        """将十六进制颜色转换为RGB"""
        try:
            hex_color = hex_color.lstrip('#')
            return tuple(int(hex_color[i:i+2], 16) for i in (0, 2, 4))
        except Exception:
            return (0, 0, 0)
    
    def _lighten_color(self, rgb_color: Tuple[int, int, int], factor: float) -> Tuple[int, int, int]:
        """使颜色变浅"""
        try:
            return tuple(min(255, int(c + (255 - c) * factor)) for c in rgb_color)
        except Exception:
            return rgb_color


# 全局样式应用器实例
style_applicator = StyleApplicator()